#include <windows.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QDebug>
#include <QRegularExpression>
#include <QDateTime>
#include <QFile>
#include <QDir>
#include <QString>
#include <QTextStream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , serialPort(new QSerialPort(this))
{
    ui->setupUi(this);
    this->setWindowTitle("纸笔记录本SN号写入工具V1.0.1");

    // 设置 SN 文件路径
    QString dateDir = QDateTime::currentDateTime().toString("yyyy-MM-dd"); // 当前日期目录
    QString snDir = QDir::currentPath() + QString("/sn/%1").arg(dateDir);
    QDir().mkpath(snDir); // 确保目录存在

    QDateTime currentTime = QDateTime::currentDateTime();
    snFileLog = snDir + QString("/B601_SN_%1.xlsx").arg(currentTime.toString("HH_mm_ss"));

    // 安装自定义日志处理
   qInstallMessageHandler(MainWindow::customMessageHandler);

    successMessageBox = nullptr;
    errorMessageBox = nullptr;

    ui->statusLabel->setText("未连接");
    ui->statusLabel->setStyleSheet("background-color: red; color: white; font-size: 16px;");

    // 绑定烧录按钮
    ui->burnButton->setEnabled(false);
    connect(ui->burnButton, &QPushButton::clicked, this, &MainWindow::startBurning);

    // 绑定输入框信号
    ui->snInput->setEnabled(false);
    connect(ui->snInput, &QLineEdit::textChanged, this, &MainWindow::handleSNInput);

    // 设置串口对象的信号和槽
    connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::onSerialPortDataReceived);
    connect(serialPort, &QSerialPort::errorOccurred, this, &MainWindow::onSerialPortDisconnected);

    // 初始化定时器，每隔2秒调用一次 autoConnectSerialPort
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &MainWindow::autoConnectSerialPort);
    timer->start(2000);

    QApplication::setStyle("Fusion");


}

MainWindow::~MainWindow()
{
    if (serialPort->isOpen()) {
        serialPort->close();
    }
    delete ui;
}

// 自动连接串口
void MainWindow::autoConnectSerialPort()
{
    // 定义 PID 和 VID
    const QString targetVid = "1A86";  // 设备的 VID
    const QString targetPid = "7523";  // 设备的 PID

    //qDebug() << "isConnected ="<< isConnected;

    // 如果串口尚未连接，继续轮询
    if (!isConnected) {
        qDebug() << "开始轮询串口";
        // 遍历所有可用的串口
        foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
            QString pid = QString::number(info.productIdentifier(), 16).toUpper();
            QString vid = QString::number(info.vendorIdentifier(), 16).toUpper();

            // 如果 PID 和 VID 匹配
            if (pid == targetPid && vid == targetVid) {
                serialPort->setPort(info); // 设置串口
                if (serialPort->open(QIODevice::ReadWrite)) {
                    qDebug() << "Serial port connected:" << info.portName();
                    // 设置串口参数
                    serialPort->setBaudRate(QSerialPort::Baud115200); // 波特率115200
                    serialPort->setDataBits(QSerialPort::Data8);      // 数据位8
                    serialPort->setParity(QSerialPort::NoParity);     // 无校验位
                    serialPort->setStopBits(QSerialPort::OneStop);    // 停止位1
                    serialPort->setFlowControl(QSerialPort::NoFlowControl); // 无流控
                    setConnected(); // 更新状态灯和 UI
                    isConnected = true;
                    qDebug() << "停止轮询";

                    if (successMessageBox) {
                        QTimer::singleShot(1000, this, [this]() {
                            successMessageBox->close(); // 关闭之前的弹框
                            delete successMessageBox;  // 删除旧的实例
                            successMessageBox = nullptr;
                        });
                    }

                    if (errorMessageBox) {
                        QTimer::singleShot(3000, this, [this]() {
                            errorMessageBox->close(); // 关闭之前的弹框
                            delete errorMessageBox;  // 删除旧的实例
                            errorMessageBox = nullptr;

                        });
                    }
                    if (ui->snInput) { // 确保 snInput 是有效指针
                        ui->snInput->setFocus();          // 聚焦到输入框
                    }

                    break;  // 成功连接后，结束轮询
                } else {
                    setDisconnected();  // 如果打开失败，状态灯保持红色
                }
            }
        }
    } else {
        //qDebug() << "串口已经连接，轮询停止";
    }
}

// 更新状态为已连接（绿色）
void MainWindow::setConnected()
{
    qInfo() << "串口连接";

    // 更新状态文本和背景颜色
    ui->statusLabel->setText("已连接");
    ui->statusLabel->setStyleSheet("background-color: green; color: white; font-size: 16px;");

    // 启用 SN 输入框
    ui->snInput->setEnabled(true);

}

// 更新状态为未连接（红色）
void MainWindow::setDisconnected()
{
    qInfo() << "串口未连接";

    // 更新状态文本和背景颜色
    ui->statusLabel->setText("未连接");
    ui->statusLabel->setStyleSheet("background-color: red; color: white; font-size: 16px;");

    // 禁用 SN 输入框和烧录按钮
    ui->snInput->setEnabled(false);
    ui->burnButton->setEnabled(false);
}

// 失败时的处理函数，退出测试环境并显示错误消息
void MainWindow::handleFailure(const QString &errorMessage)
{
    commandQueue.clear();
    qWarning() << "清空指令队列";
    // 设置进度条为红色，表示失败
    ui->writeProgress->setStyleSheet("QProgressBar::chunk { background-color: red; }");

    // 弹出错误提示框
    errorMessageBox = new QMessageBox(QMessageBox::Critical, "烧录失败", errorMessage, QMessageBox::Ok, this);
    errorMessageBox->show();

    // 退出测试环境
    burnState = StateExitFactory;
    serialPort->write("{\"cmd\": \"exit_test_env\"}\n");

    // 清空输入框并重置按钮
    ui->snInput->clear();
    ui->burnButton->setEnabled(false);
    ui->snInput->setEnabled(false);
    setDisconnected();

    QTimer::singleShot(2000, this, [=]() {
        if (serialPort->isOpen()) {
            serialPort->close();  // 先关闭串口，避免重复连接
            qDebug() << "延时关闭串口，确保退出测试环境 再轮询串口";
            isConnected = false;
        }
    });
}

// 串口连接后的槽函数
void MainWindow::onSerialPortDataReceived()
{
    //qDebug() << "串口有数据";

    static QByteArray responseBuffer;

    // 累积串口返回的数据
    responseBuffer.append(serialPort->readAll());

    // 判断是否接收到完整的 JSON 响应
    if (!responseBuffer.contains("}")) {
        return; // 如果未接收到完整的JSON，继续等待
    }

    QByteArray response = responseBuffer.trimmed();
    responseBuffer.clear(); // 清空缓冲区，防止重复处理
    qDebug() << "接收到指令返回:" << response;

    // 清理空字节和指令回显
    response.replace("\x00", "");
    response.remove(0, response.indexOf('{')); // 去掉非 JSON 的部分
    qDebug() << "处理后的指令返回:" << response;

    // 解析 JSON 数据
    QJsonDocument jsonResponse = QJsonDocument::fromJson(response);
    if (!jsonResponse.isObject()) {
        qWarning() << "解析失败：收到的数据不是有效的JSON";
        return;
    }

    QJsonObject jsonObject = jsonResponse.object();
    QString result = jsonObject.value("result").toString();

    // 根据当前状态机状态处理返回的数据
    switch (burnState) {
    case StateEnterFactory:
        if (result == "success") {
            qInfo() << "进入测试环境成功";
            burnState = StateSnSet;
            ui->writeProgress->setValue(20);
            sendNextCommand();
        } else {
            ui->writeProgress->setStyleSheet("QProgressBar::chunk { background-color: red; }");
            qWarning() << "进入测试环境失败！";
            handleFailure("进入测试环境失败！");
        }
        break;

    case StateSnSet:
        if (result == "success") {
            qInfo() << "SN 写入成功";
            burnState = StateSnGet;
            ui->writeProgress->setValue(30);
            sendNextCommand();
            ui->writeProgress->setValue(40);
        } else if (result == "fail") {
             writeError = jsonObject.value("msg").toString();
            qWarning() << "SN 写入失败，错误消息:" << writeError;
            handleFailure("SN 写入失败，错误消息: " + writeError);
        }
        break;

    case StateSnGet:
        if (result == "success") {
            readSnData = jsonObject["sn"].toString();
            qDebug() << "读取到的 SN 值:" << readSnData;
            burnState = StateMacRead;
            sendNextCommand();
            ui->writeProgress->setValue(50);
        } else if (result == "fail") {
            qWarning() << "读取 SN 失败";
            handleFailure("读取 SN 失败");
        }
        break;

    case StateMacRead:
        if (result == "success") {
            macAddress = jsonObject["mac"].toString();
            qDebug() << "读取到的 MAC 地址:" << macAddress;
            burnState = StateExitFactory;
            ui->writeProgress->setValue(60);
            sendNextCommand();
            ui->writeProgress->setValue(70);
        } else if (result == "fail") {
            qWarning() << "读取 MAC 失败";
            handleFailure("读取 MAC 地址失败");
        }
        break;

    case StateExitFactory:
        if (result == "success") {
            qInfo() << "退出测试环境成功";
            burnState = StateIdle;
            if (ui->writeProgress->value() == 70) {
                ui->writeProgress->setValue(80);
                compareSn();
            }
        } else {
            qWarning() << "退出测试环境失败！";
            handleFailure("退出测试环境失败！");
        }
        break;

    default:
        qWarning() << "未知的状态，忽略此返回";
        break;
    }
}

// 串口断开后的槽函数
void MainWindow::onSerialPortDisconnected()
{
    if (isConnected) {
        qWarning() << "串口断开";
        setDisconnected(); // 更新状态灯和 UI
        isConnected = false;
        if (serialPort->isOpen()) {
            serialPort->close();  // 先关闭串口，避免重复连接
            qDebug() << "串口已关闭，准备重新连接";
        }
    }
}

// 动态计算当前年份字符
QString MainWindow::getYearChar(int year)
{
    if (year < 2018) {
        return QString(); // 不支持2018年之前的年份
    }

    int diff = year - 2018;
    if (diff < 2) {
        return QString::number(8 + diff); // 2018~2019 对应数字 8 和 9
    }

    // 显式将结果转换为 QChar
    return QString(QChar('A' + diff - 2)); // 2020年开始对应 A, B, ...
}

// 校验 SN 格式（长度和格式校验）
bool MainWindow::validateSN(const QString &sn)
{
    const int requiredLength = 18; // SN 长度必须为 18
    if (sn.length() != requiredLength) {
        return false;
    }

    QString currentYearChar = getYearChar(QDate::currentDate().year());

    // 匹配 SN 格式
    // 产品型号 9位: 固定为 XFDXX1B6E
    // 年份 1位: 2018年为8, 2019年为9, 2020年为A, 2021年为B, 2024年为E
    // 周数 2位: 01 ~ 52
    // 定制标识 1位: 固定为 0
    // 序号 5位: 00001 ~ 99999
    QString regexPattern = QString("^XFDXX1B6E[%1][0-5][0-9]0[0-9]{5}$")
                               .arg(currentYearChar);
    QRegularExpression snRegex(regexPattern);
    QRegularExpressionMatch match = snRegex.match(sn);
    if (!match.hasMatch()) {
        return false;
    }

    // 校验周数范围是否有效 (01 ~ 52)
    int week = sn.mid(10, 2).toInt();
    if (week < 1 || week > 52) {
        return false;
    }

    return true;
}

// 处理扫码枪输入
void MainWindow::handleSNInput()
{
    //qDebug() << "SN 输入框内容变化";
    QString sn = ui->snInput->text();

    // 校验 SN 格式
    if (sn.length() == 18) {
        ui->burnButton->setEnabled(true);
        qDebug() << "可以烧录";
    }
}

// 开始烧录任务
void MainWindow::startBurning()
{
    QString sn = ui->snInput->text();

    // 校验 SN 格式
    if (!validateSN(sn)) {
        QMessageBox::critical(this, "SN 校验失败", "SN 格式不正确！\n\n"
                                                   "格式应为:\n"
                                                   "XFDXX1B6E + 年份(1位) + 周数(2位) + 定制标识(1位: 0) + 序号(5位)");
        return; // 禁止烧录
    }

    qWarning() << "点击按钮开始烧录";

    // 禁用输入框和按钮
    ui->snInput->setEnabled(false);
    ui->burnButton->setEnabled(false);

    // 显示进度条并初始化
    ui->writeProgress->setVisible(true);
    ui->writeProgress->setValue(0);
    ui->writeProgress->setStyleSheet("");

    // 发送第一条指令
    ui->writeProgress->setValue(10);
    sendNextCommand();
}

void MainWindow::compareSn(){

    ui->writeProgress->setValue(90);
    QString sn = ui->snInput->text();

    // 比对写入和读取的 SN
    if (readSnData == sn) {
        //if (1) {

        ui->writeProgress->setValue(100);
        // 格式化显示内容
        QString formattedSN = QString("%1").arg(sn);

        // 添加到左侧列表
        ui->snList->addItem(formattedSN);

        // 更新 countLabel 显示当前烧录成功的数量
        ui->countLabel->setText(QString("共计烧录数量: %1").arg(snCounter++));

        // 将 SN 和 MAC 地址追加到日志文件
        QString formattedLog = QString("%1  &  %2").arg(sn).arg(macAddress);
        QFile logFile(snFileLog);
        if (logFile.open(QIODevice::Append | QIODevice::Text)) {
            QTextStream out(&logFile);
            out << formattedLog << "\n";
            logFile.close();
        } else {
            qWarning() << "无法打开日志文件:" << snFileLog;
        }

        // 弹出烧录成功消息框
        successMessageBox = new QMessageBox(QMessageBox::Information, "烧录成功", "SN号烧录成功！", QMessageBox::Ok, this);
        successMessageBox->show();

    } else {
        // 对比失败
        qWarning() << "对比sn不一致";
        ui->writeProgress->setStyleSheet("QProgressBar::chunk { background-color: red; }"); // 变红

        // 如果对比失败，显示错误描述
        errorMessageBox = new QMessageBox(QMessageBox::Critical, "烧录失败!", writeError, QMessageBox::Ok, this);
        errorMessageBox->show();
    }

    // 清空输入框并重置按钮
    isConnected = false;
    ui->snInput->clear();
    ui->burnButton->setEnabled(false);
    ui->snInput->setEnabled(false);
    setDisconnected();

    QTimer::singleShot(2000, this, [=]() {
        if (serialPort->isOpen()) {
            serialPort->close();  // 先关闭串口，避免重复连接
            qDebug() << "延时关闭串口，确保退出测试环境";
        }
    });

}

void MainWindow::customMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
{
    QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
    QString dateDir = QDateTime::currentDateTime().toString("yyyy-MM-dd"); // 当前日期目录
    QString logLevel;

    switch (type) {
    case QtDebugMsg:
        logLevel = "[DEBUG]   ";
        break;
    case QtWarningMsg:
        logLevel = "[WARNING] ";
        break;
    case QtCriticalMsg:
        logLevel = "[CRITICAL]";
        break;
    case QtFatalMsg:
        logLevel = "[FATAL]   ";
        break;
    case QtInfoMsg:
        logLevel = "[INFO]    ";
        break;
    }

    QString logEntry = QString("[%1] %2 %3").arg(timestamp).arg(logLevel).arg(msg);

    // 日志目录路径
    QString logDir = QDir::currentPath() + QString("/log/%1").arg(dateDir);
    QDir().mkpath(logDir); // 确保目录存在

    // 日志文件路径
    QString logFilePath = logDir + "/B601_log.txt";

    QFile logFile(logFilePath);
    if (logFile.open(QIODevice::Append | QIODevice::Text)) {
        QTextStream out(&logFile);

        static bool firstLog = true;
        if (firstLog) {
            out << "========================= Log Start =========================\n";
            firstLog = false;
        }

        out << logEntry << "\n";

        logFile.close();
    }
}


